package cn.growthgate.fgo.config;

import org.apache.shiro.authc.credential.AllowAllCredentialsMatcher;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.codec.Base64;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.cache.ehcache.EhCacheManagerFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import cn.growthgate.fgo.core.shiro.ShiroDbRealm;
import cn.growthgate.fgo.util.AuthenticationUtils;

/**
 * shiro配置
 * 
 * @author GrowthGate
 * @since 2019年1月23日
 *
 */
@Configuration
public class ShiroConfig {
	
	/**
	 * 开启Shiro的注解(如@RequiresRoles,@RequiresPermissions),需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证
	 * 配置以下两个bean(DefaultAdvisorAutoProxyCreator和AuthorizationAttributeSourceAdvisor)即可实现此功能
	 * 
	 * @return
	 */
	@Bean
	public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
		DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
		advisorAutoProxyCreator.setProxyTargetClass(true);
		return advisorAutoProxyCreator;
	}
	
	/**
	 * 开启aop注解支持
	 * 
	 * @param securityManager
	 * @return
	 */
	@Bean
	public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
		AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
		authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
		return authorizationAttributeSourceAdvisor;
	}

	/**
	 * 缓存管理器 使用Ehcache实现
	 */
	@Bean
	public CacheManager getCacheShiroManager(EhCacheManagerFactoryBean ehcache) {
		EhCacheManager ehCacheManager = new EhCacheManager();
		ehCacheManager.setCacheManager(ehcache.getObject());
		return ehCacheManager;
	}
	
	/**
	 * 记住密码cookie
	 * 
	 * @return
	 */
	@Bean
	public SimpleCookie rememberMeCookie() {
		SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
		simpleCookie.setHttpOnly(true);
		simpleCookie.setMaxAge(7 * 24 * 60 * 60);// 7天
		return simpleCookie;
	}

	@Bean
	public CookieRememberMeManager cookieRememberMeManager() {
		CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
		cookieRememberMeManager.setCookie(rememberMeCookie());
		// AES密钥
		cookieRememberMeManager.setCipherKey(Base64.decode("7iHpav4W4Hh2BrXBA2e7Vg=="));
		return cookieRememberMeManager;
	}
	
	@Bean
	public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
		ShiroFilterFactoryBean sffb = new ShiroFilterFactoryBean();
		// 必须设置 SecurityManager
		sffb.setSecurityManager(securityManager);

		// 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
		sffb.setLoginUrl(AuthenticationUtils.DEFAULT_LOGIN_URL);
		sffb.setSuccessUrl(AuthenticationUtils.DEFAULT_SUCCESS_URL);
		sffb.setUnauthorizedUrl(AuthenticationUtils.DEFAULT_UNAUTHORIZED_URL);

		// 拦截器.
		// Map<String, String> filterChainDefinitionMap = new
		// LinkedHashMap<String, String>();
		// 配置不会被拦截的链接 顺序判断
		// filterChainDefinitionMap.put("/static/**", "anon");
		// 配置退出过滤器,其中的具体的退出代码Shiro已经替我们实现了
		// filterChainDefinitionMap.put("/logout", "logout");
		// 过滤链定义，从上向下顺序执行，一般将 /**放在最为下边
		// <!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问-->
		// filterChainDefinitionMap.put("/", "user");
		// filterChainDefinitionMap.put("/**", "authc");
		// sffb.setFilterChainDefinitionMap(filterChainDefinitionMap);
		return sffb;
	}

	@Bean
	public SecurityManager securityManager(CacheManager cacheManager) {
		DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
		securityManager.setRealm(shiroDbRealm());
		securityManager.setRememberMeManager(cookieRememberMeManager());
		securityManager.setCacheManager(cacheManager);
		return securityManager;
	}

	/**
	 * 项目自定义的realm
	 * 
	 * @return
	 */
	@Bean
	public ShiroDbRealm shiroDbRealm() {
		ShiroDbRealm shiroDbRealm = new ShiroDbRealm();
		shiroDbRealm.setCredentialsMatcher(new AllowAllCredentialsMatcher());
		return shiroDbRealm;
	}

}
